﻿//===================================================================================
// Copyright (c) Ryan Garrett.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===================================================================================

using System;
using System.Collections;
using System.Collections.Generic;
using Caffeine.Core.Metadata;

namespace Caffeine.Core
{
    /// <summary>
    /// Collection for models
    /// </summary>
    public abstract class ModelCollectionBase : ModelPropertyBase, IEnumerable<ModelBase>, IEnumerable
    {
        #region Constructors

        internal ModelCollectionBase(ModelBase parent, String name, Nullable<ModelPropertyBehaviors> behavior, Boolean isWrapped)
            : base(parent, name, behavior, isWrapped)
        {
        }

        #endregion

        #region Public

        /// <summary>
        /// Gets whether or not this collection is readonly
        /// </summary>
        public abstract Boolean IsReadOnly
        {
            get;
        }

        /// <summary>
        /// Gets whether or not there are any models added to this collection. This property supports INPC.
        /// </summary>
        public abstract Boolean ContainsAddedModels
        {
            get;
            protected set;
        }

        /// <summary>
        /// Gets whether or not there are any models removed from this collection. This property supports INPC.
        /// </summary>
        public abstract Boolean ContainsRemovedModels
        {
            get;
            protected set;
        }

        /// <summary>
        /// Gets whether or not there are any models committed to this collection. This property supports INPC.
        /// </summary>
        public abstract Boolean ContainsCommittedModels
        {
            get;
            protected set;
        }

        /// <summary>
        /// Gets the number of added or committed models. This property supports INPC.
        /// </summary>
        public abstract Int32 Count
        {
            get;
        }

        /// <summary>
        /// Gets the number of models added to this collection. This property supports INPC.
        /// </summary>
        public abstract Int32 AddedModelCount
        {
            get;
            protected set;
        }

        /// <summary>
        /// Gets the number of models removed from this collection. This property supports INPC.
        /// </summary>
        public abstract Int32 RemovedModelCount
        {
            get;
            protected set;
        }

        /// <summary>
        /// Gets the number of models committed to this collection. This property supports INPC.
        /// </summary>
        public abstract Int32 CommittedModelCount
        {
            get;
            protected set;
        }

        /// <summary>
        /// Will always return false
        /// </summary>
        public override sealed Boolean IsModelProperty
        {
            get
            {
                return false;
            }
        }

        /// <summary>
        /// Will always return true
        /// </summary>
        public override sealed Boolean IsModelCollectionProperty
        {
            get
            {
                return true;
            }
        }

        /// <summary>
        /// Gets an enumeration of all added or commited models in this collection
        /// </summary>
        /// <returns>An enumeration of all added or commited models in this collection</returns>
        public abstract IEnumerator<ModelBase> GetEnumerator();

        /// <summary>
        /// Gets an enumeration of all models added to this collection
        /// </summary>
        /// <returns>An enumeration of all models added to this collection</returns>
        public abstract IEnumerable<ModelBase> GetAddedModels();

        /// <summary>
        /// Gets an enumeration of all models committed to this collection
        /// </summary>
        /// <returns>An enumeration of all models committed to this collection</returns>
        public abstract IEnumerable<ModelBase> GetCommittedModels();

        /// <summary>
        /// Gets an enumeration of all models removed from this collection
        /// </summary>
        /// <returns>An enumeration of all models removed from this collection</returns>
        public abstract IEnumerable<ModelBase> GetRemovedModels();

        /// <summary>
        /// Gets an enumeration of all added or commited models in this collection
        /// </summary>
        /// <returns>An enumeration of all added or commited models in this collection</returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion

        #region Internal

        internal abstract Boolean SupportsPropertyChangeTracking
        {
            get;
        }

        internal abstract ModelCollectionMetadata GetMetadata();

        internal abstract Object GetCollectionChangedForTesting();

        internal abstract Object GetValidationMethodForTesting();

        internal void ApplyCollectionMetadata(ModelCollectionMetadata metadata, IModelFactory factory)
        {
            ApplyPropertyMetadata(metadata);
            OnApplyCollectionMetadata(metadata, factory);
        }

        #endregion

        #region Protected

        protected abstract void OnApplyCollectionMetadata(ModelCollectionMetadata metadata, IModelFactory factory);

        #endregion
    }
}
